# 处理扫码支付
import json
import threading
import time
from decimal import Decimal

from django.db import connection, transaction

from app.my_exception import MyException
from app.service import app_order, order, web_socket, app_api
from app.service.ali import Ali
from app.service.wx import WxPay
from libs import time_helper, common
from libs.common import get_ts
from libs.db import DB


# result_code 有三种状态 SUCCESS 成功,FAIL 失败和未知
def process_scan_code_pay(third_party_pay_flag, pay_code, third_party_pay_data, cashier_id):
    third_party_order_sn = ''
    third_party_resp = {}
    result_code = ''
    pay_typ_name = ''
    pay_fen = third_party_pay_data.get('pay_fen')
    order_sn = third_party_pay_data.get('order_sn')
    if pay_fen is None or pay_fen == 0:
        return 'SUCCESS', third_party_order_sn, third_party_resp, None
    try:
        if third_party_pay_flag == 1:
            pay_typ_name = '微信'
            desc = '信资商城微信支付'
            result_code, third_party_order_sn, third_party_resp, err = WxPay().barcodePay(pay_code,
                                                                                          order_sn,
                                                                                          pay_fen,
                                                                                          desc)
        elif third_party_pay_flag == 2:
            pay_typ_name = '支付宝'
            desc = '信资商城支付宝支付'
            result_code, third_party_order_sn, third_party_resp, err = Ali().barcodePay(pay_code,
                                                                                        order_sn,
                                                                                        pay_fen,
                                                                                        desc)
        else:
            err = '无效的支付方式'
    except Exception as e:
        print(e)
        err = '支付异常'
    if err is None:
        yuan = common.fen_to_yuan(pay_fen)
        msg = '{}到账{}元'.format(pay_typ_name, yuan)
        web_socket.notice_payment(cashier_id, msg)
    return result_code, third_party_order_sn, third_party_resp, err


def update_third_party_pay_log(cursor, pay_log_data, where):
    err = None
    db = DB('cs_order_pay_logs', conn=cursor)
    affected = db.update(pay_log_data, where)
    if affected == 0:
        err = '支付状态未更新'
    return err


# 处理第三方支付订单支付成功
def process_tp_payment_order_success(cs_order_id, pay_log_data, where):
    # 确认支付成功，更新第三方支付订单支付状态
    with connection.cursor() as cursor:
        try:
            with transaction.atomic():
                err = update_third_party_pay_log(cursor, pay_log_data, where)
                if err is not None:
                    raise MyException(err)
                db = DB('cs_orders', conn=cursor)
                db_order = db.one(['id', 'cart_typ'], {'id': cs_order_id})
                db_order_id = db_order.get('id', 0)
                if db_order_id == 0:
                    raise MyException('消费订单不存在')
                db_order_cart_typ = db_order.get('cart_typ')
                new_order_status = 1
                new_app_order_state = 7
                if db_order_cart_typ in [1, 2, 3]:
                    new_order_status = -5
                    new_app_order_state = 11

                # 忽略更新订单状态失败，可通过定时任务补状态
                db.update({'status': new_order_status}, {'id': cs_order_id})
                app_order_data = {
                    'pay_time': time_helper.ts_to_time_str(time_format="%Y-%m-%d %H:%M:%S")
                }
                err = app_order.update_order_status(cursor, cs_order_id, new_app_order_state, app_order_data)
                if err is not None:
                    raise MyException(err)
        except MyException as e:
            err = str(e)
        except Exception as e:
            err = '处理第三方支付订单异常'
            print(err, e)
    return err


# 处理第三方支付订单支付失败
def process_tp_payment_order_fail(cs_order_id, pay_log_data, where, trade_state_desc):
    # 确认支付成功，更新第三方支付订单支付状态
    with connection.cursor() as cursor:
        try:
            with transaction.atomic():
                err = update_third_party_pay_log(cursor, pay_log_data, where)
                if err is not None:
                    raise MyException(err)
                db = DB('cs_orders', conn=cursor)
                db.update({'status': -3, 'trade_state_desc': trade_state_desc}, {'id': cs_order_id})
                err = order.recover_stock_from_order(cursor, cs_order_id)
                if err is not None:
                    raise MyException(err)
                err = app_order.update_order_status(cursor, cs_order_id, 4)
                if err is not None:
                    raise MyException(err)
        except MyException as e:
            err = str(e)
        except Exception as e:
            err = '处理第三方支付订单异常'
            print(err, e)
    return err


def gen_pay_order_sn(order_typ):
    order_typ = str(order_typ).zfill(2)
    date_str = time_helper.ts_to_time_str(time_format="%y%m%d%H%M%S")
    rand_num = common.rand_str(6, 4)
    return '{}{}{}'.format(date_str, order_typ, rand_num)


def create_top_up_order(cursor, order_data):
    now = get_ts()
    data = {
        'order_typ': 2,
        'tp_status': 0,
        'created': now,
        'updated': now,
    }
    data.update(order_data)
    db = DB('cs_tp_logs', conn=cursor)
    return db.insert(data)


def get_third_party_pay_order(cursor, order_sn, fields=None):
    if fields is None:
        fields = ['id', 'order_args', 'pay_yuan', 'confirmed']
    db = DB('cs_tp_logs', conn=cursor)
    return db.one(fields, {'order_sn': order_sn})


def loop_query_pay_status(order_sn):
    for i in range(3):
        result_code, trade_state, err = order.is_third_party_order_sync_state('order_sn', order_sn)
        if result_code in ['SUCCESS', 'FAIL']:
            break
        elif trade_state == 'USERPAYING':
            sec = (i + 1) * 10
            time.sleep(sec)
        if err is not None:
            print('loop_query_pay_status err:', err)
        time_str = time_helper.ts_to_time_str(None, '%Y-%m-%d %H:%M:%S')
        print('loop_query_pay_status time：', time_str)


# 异步查询支付状态
def async_query_pay_status(order_sn):
    th = threading.Thread(target=loop_query_pay_status, args=(order_sn,))
    th.start()


# 处理购物车支付
def process_cart_payment(cashier_id,
                         cs_order_id,
                         order_sn,
                         pay_log_id,
                         third_party_pay_flag,
                         pay_code,
                         third_party_pay_data, ):
    result_code, third_party_order_sn, third_party_resp, err = process_scan_code_pay(
        third_party_pay_flag,
        pay_code,
        third_party_pay_data,
        cashier_id
    )
    if type(err) is str:
        err_msg = err
    else:
        err_msg = ''
    pay_result = {
        'result_code': result_code,
        'trade_no': third_party_order_sn,
    }

    third_party_resp_str = ''
    trade_state_desc = ''
    try:
        third_party_resp_str = json.dumps(third_party_resp)
        trade_state_desc = third_party_resp.get('trade_state_desc', '')
    except Exception as e:
        print(e)
        err_msg = '第三方支付响应格式错误'

    now = get_ts()
    if result_code == 'SUCCESS':
        pay_log_data = {
            'confirmed': now,
            'tp_order_sn': third_party_order_sn,
            'tp_status': 1,
            'tp_order_detail': third_party_resp_str,
            'err': err_msg,
            'updated': now
        }
        where = {'id': pay_log_id}
        err = process_tp_payment_order_success(cs_order_id, pay_log_data, where)
        return pay_result, err
    elif result_code == 'FAIL':
        pay_log_data = {
            'confirmed': now,
            'tp_status': -1,
            'tp_order_detail': third_party_resp_str,
            'err': err_msg,
            'updated': now
        }
        where = {'id': pay_log_id}
        err = process_tp_payment_order_fail(cs_order_id, pay_log_data, where, trade_state_desc)
        if err is not None:
            return pay_result, err
        if err_msg == '':
            err = '订单支付失败'
        return pay_result, err
    else:
        # 后台同步订单支付状态
        async_query_pay_status(order_sn)
        return pay_result, '支付订单状态处理中，请稍后确认'


# 处理会员充值支付
def process_top_up_payment(cashier_id,
                           order_sn,
                           third_party_pay_flag,
                           pay_code):
    with connection.cursor() as cursor:
        pay_result = {}
        # 判断订单号是否存在
        pay_order_data = get_third_party_pay_order(cursor, order_sn)
        pay_order_id = pay_order_data.get('id', 0)
        if pay_order_id == 0:
            return pay_result, '支付订单不存在'
        pay_order_confirmed = pay_order_data.get('confirmed')
        if pay_order_confirmed > 0:
            date_str = time_helper.ts_to_time_str(pay_order_confirmed, time_format='%Y-%m-%d %H:%M:%S')
            err = '该订单已支付，支付时间{}'.format(date_str)
            return pay_result, err
        order_args_str = pay_order_data.get('order_args', '')
        try:
            order_args = json.loads(order_args_str)
        except Exception:
            return pay_result, '无效的充值参数'
        pay_yuan = pay_order_data.get('pay_yuan')
        pay_fen = int(pay_yuan * Decimal('100'))
        third_party_pay_data = {
            'pay_fen': pay_fen,
            'order_sn': order_sn
        }
        result_code, third_party_order_sn, third_party_resp, err = process_scan_code_pay(
            third_party_pay_flag,
            pay_code,
            third_party_pay_data,
            cashier_id
        )

        third_party_resp_str = ''
        try:
            third_party_resp_str = json.dumps(third_party_resp)
        except Exception as e:
            print(e)
            err = '第三方支付响应格式错误'

        db = DB('cs_tp_logs', conn=cursor)
        if err is not None:
            db.update({
                'err': err,
            }, {
                'id': pay_order_id
            })
            return pay_result, err
        pay_result = {
            'result_code': result_code,
            'trade_no': third_party_order_sn,
        }
        affected, _ = db.update({
            'pay_code': pay_code,
            'tp_order_sn': third_party_order_sn,
            'tp_order_detail': third_party_resp_str,
            'tp_status': 1,
            'mark_no': '',
        }, {
            'id': pay_order_id
        })
        if affected < 1:
            return pay_result, '更新支付订单失败'
        card_id = order_args.get('card_id')
        username = order_args.get('username')
        pay_mode = order_args.get('pay_mode')
        num = order_args.get('num')
        err = app_api.app_top_up(cashier_id, order_sn, card_id, username, pay_mode, num)
    return pay_result, err

# 处理快餐店会员充值支付
def process_top_up_payment_fast(cashier_id,
                           order_sn,
                           third_party_pay_flag,
                           pay_code,
                           username,
                           pay_mode,
                           realmoney,
                           chargemoney,
                           type_id):
    with connection.cursor() as cursor:
        pay_result = {}
        # 判断订单号是否存在
        pay_order_data = get_third_party_pay_order(cursor, order_sn)
        pay_order_id = pay_order_data.get('id', 0)
        if pay_order_id == 0:
            return pay_result, '支付订单不存在'
        pay_order_confirmed = pay_order_data.get('confirmed')
        if pay_order_confirmed > 0:
            date_str = time_helper.ts_to_time_str(pay_order_confirmed, time_format='%Y-%m-%d %H:%M:%S')
            err = '该订单已支付，支付时间{}'.format(date_str)
            return pay_result, err
        pay_yuan = pay_order_data.get('pay_yuan')
        pay_fen = int(pay_yuan * Decimal('100'))
        third_party_pay_data = {
            'pay_fen': pay_fen,
            'order_sn': order_sn
        }
        result_code, third_party_order_sn, third_party_resp, err = process_scan_code_pay(
            third_party_pay_flag,
            pay_code,
            third_party_pay_data,
            cashier_id
        )

        third_party_resp_str = ''
        try:
            third_party_resp_str = json.dumps(third_party_resp)
        except Exception as e:
            print(e)
            err = '第三方支付响应格式错误'

        db = DB('cs_tp_logs', conn=cursor)
        if err is not None:
            db.update({
                'err': err,
            }, {
                'id': pay_order_id
            })
            return pay_result, err
        pay_result = {
            'result_code': result_code,
            'trade_no': third_party_order_sn,
        }
        affected, _ = db.update({
            'pay_code': pay_code,
            'tp_order_sn': third_party_order_sn,
            'tp_order_detail': third_party_resp_str,
            'tp_status': 1,
            'mark_no': '',
        }, {
            'id': pay_order_id
        })
        if affected < 1:
            return pay_result, '更新支付订单失败'
        u_info = DB('table_member',conn=cursor).one(['id','username','fast_ballance'],{'username':username})
        before_ballance = u_info.get('fast_ballance',0)
        after_ballance = before_ballance + realmoney
        DB('table_member',conn=cursor).update({'fast_ballance': after_ballance,'is_fastmember':1},{'username':username})
        insert_flow = {
            'username':username,
            'before_value':before_ballance,
            'after_value':after_ballance,
            'amount':realmoney,
            'type':1,
            'charge_type':type_id,
            'charge_mode':pay_mode,
            'charge_money':chargemoney,
            'charge_ordersn':order_sn
        }
        DB('table_fastballance_flow',conn=cursor).insert(insert_flow)
        err = None
    return pay_result, err

def check_post_payments(pay_methods):
    err = None
    pay_method = ''
    selected_pay_method_dic = {}
    post_pay_total = Decimal('0')
    # 用户需要支付
    pay_method_len = len(pay_methods)
    if pay_method_len == 0:
        return post_pay_total, pay_method, selected_pay_method_dic, '请至少选择一种付款方式'
    pay_typ_dic = order.PaymentMethodDict
    try:
        pay_method_arr = []
        pay_methods = order.sort_pay_methods(pay_methods)
        for pay_data in pay_methods:
            val_typ = type(pay_data)
            if val_typ is not dict:
                return post_pay_total, pay_method, selected_pay_method_dic, '存在无效的付款方式'
            pay_typ = int(pay_data.get('typ'))
            if pay_typ not in pay_typ_dic:
                return post_pay_total, pay_method, selected_pay_method_dic, '存在无效的付款方式'
            pay_method_arr.append(pay_typ_dic.get(pay_typ))
            pay_amount = Decimal(str(pay_data.get('amount'))).quantize(Decimal('0.00'))
            if pay_amount < 0:
                return post_pay_total, pay_method, selected_pay_method_dic, '付款总额不能小于0'
            post_pay_total += pay_amount
            selected_pay_method_dic[pay_typ] = {'pay_amount': pay_amount}
        pay_method = '+'.join(pay_method_arr)
    except Exception as e:
        err = '存在无效的付款方式'
        print(err, e)
        return post_pay_total, pay_method, selected_pay_method_dic, err
    return post_pay_total, pay_method, selected_pay_method_dic, err
